﻿using System;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Threading;
using Iot.AlarmDispose.Database;
using Iot.AlarmDispose.Database.Entities;
using Iot.Shared.Enums;
using Iot.Shared.Helper;
using Iot.Shared.Model;
using Iot.Shared.Path;
using Microsoft.Extensions.Logging;

namespace Iot.AlarmDispose;

public class AlertBus<TAlertClassify, TAlertsHistory> : AlertReceive, IAlertBus<TAlertClassify, TAlertsHistory>
    where TAlertClassify : class, IAlertClassify
    where TAlertsHistory : class, IAlertsHistory<TAlertClassify>
{
    /// <summary>
    ///     警告工厂，用于创建警告
    /// </summary>
    private readonly IAlertsFactory<TAlertClassify, TAlertsHistory> _alertsFactory;


    /// <summary>
    ///     用于记录当前报警
    /// </summary>
    private readonly Dictionary<DevicePath, TAlertsHistory> _currentAlarm = [];

    /// <summary>
    ///     告警历史记录
    /// </summary>
    private readonly IHistoricalRecord<TAlertClassify, TAlertsHistory>? _historicalRecord;

    /// <summary>
    ///     日志，用于记录日志
    /// </summary>
    private readonly ILogger<AlertBus<TAlertClassify, TAlertsHistory>> _logger;

    /// <summary>
    ///     定义一个阻塞集合，用于存储告警数据
    /// </summary>
    private readonly BlockingCollection<SwitchData<TAlertClassify>> _queue = [];

    /// <summary>
    ///     实时警告列表，用于存储实时警告
    /// </summary>
    private readonly IRealTimeAlertList<TAlertClassify, TAlertsHistory> _realAlert;

    /// <summary>
    ///     字典 存储了设备路径和对应的分类
    /// </summary>
    private FrozenDictionary<DevicePath, TAlertClassify>? _alertClassifyDict;


    /// <summary>
    /// </summary>
    /// <param name="alertsFactory">报警工厂接口  使用报警状态和报警分类创建报警历史记录</param>
    /// <param name="realAlert">实时显示报警列表</param>
    /// <param name="logger">日志接口</param>
    public AlertBus(
        IAlertsFactory<TAlertClassify, TAlertsHistory> alertsFactory,
        IRealTimeAlertList<TAlertClassify, TAlertsHistory> realAlert
        , ILogger<AlertBus<TAlertClassify, TAlertsHistory>> logger)
    {
        logger.LogInformation("{函数}开始初始化。", nameof(AlertBus<TAlertClassify, TAlertsHistory>)); // 记录日志
        _alertsFactory = alertsFactory; // 初始化_alertsFactory
        _realAlert = realAlert; // 初始化_realAlert
        _logger = logger; // 初始化_logger
        ThreadHelper.Run(RunAsync, ThreadPriority.AboveNormal, true, "报警信息处理线程开启失败", logger);
        logger.LogInformation("{函数}初始化完成。", nameof(AlertBus<TAlertClassify, TAlertsHistory>)); // 记录日志
    }

    /// <summary>
    /// </summary>
    /// <param name="alertsFactory">报警工厂接口  使用报警状态和报警分类创建报警历史记录</param>
    /// <param name="realAlert">实时显示报警列表</param>
    /// <param name="alertsHistory">告警历史记录</param>
    /// <param name="logger">日志接口</param>
    public AlertBus(
        IAlertsFactory<TAlertClassify, TAlertsHistory> alertsFactory,
        IRealTimeAlertList<TAlertClassify, TAlertsHistory> realAlert,
        IHistoricalRecord<TAlertClassify, TAlertsHistory> alertsHistory
        , ILogger<AlertBus<TAlertClassify, TAlertsHistory>> logger)
    {
        logger.LogInformation("{函数}开始初始化。", nameof(AlertBus<TAlertClassify, TAlertsHistory>)); // 记录日志
        _alertsFactory = alertsFactory; // 初始化_alertsFactory
        _realAlert = realAlert; // 初始化_realAlert
        _historicalRecord = alertsHistory; // 初始化_historicalRecord
        _logger = logger; // 初始化_logger
        ThreadHelper.Run(RunAsync, ThreadPriority.AboveNormal, true, "报警信息处理线程开启失败", logger);
        logger.LogInformation("{函数}初始化完成。", nameof(AlertBus<TAlertClassify, TAlertsHistory>)); // 记录日志
    }

    /// <summary>
    ///     实时告警显示接口
    /// </summary>
    public IReadRealTimeAlertList<TAlertClassify, TAlertsHistory> ReadRealTimeAlertList => _realAlert;


    /// <summary>
    ///     定义一个事件，当更新时触发
    /// </summary>
    public event Action<int>? AlertUpDateEvent;

    /// <summary>
    ///     定义一个事件，当每次更新时触发
    /// </summary>
    public event Action<int>? AlertEveryTimeUpDateEvent;


    /// <summary>
    ///     设置需要处理的告警对象
    /// </summary>
    /// <param name="data"></param>
    public void SetAlertClassify(IEnumerable<TAlertClassify> data)
    {
        _alertClassifyDict = data.ToFrozenDictionary(static a => a.Path.Resolver());
    }

    protected override void SwitchHandle(SwitchBusModel data)
    {
        if (_alertClassifyDict is null) return;
        try
        {
            // 记录日志，表示开始处理实时告警
            _logger.LogTrace("{函数}实时告警:{报警}，开始处理。", nameof(Handle), data);
            // 尝试获取报警路径对应的分类
            if (_alertClassifyDict.TryGetValue(data.Path, out var classify))
            {
                // 记录日志，表示报警被加入报警队列
                _logger.LogTrace("{函数}实时告警:{报警},加入报警队列。", nameof(Handle), data);
                // 将数据和分类添加到队列
                _queue.TryAdd(new SwitchData<TAlertClassify>(data, classify));
            }
            else
            {
                _logger.LogTrace("{函数}实时告警:{报警},未知告警路径。", nameof(Handle), data);
            }
        }
        catch (Exception ex)
        {
            // 记录日志，表示写入队列失败
            _logger.LogError(ex, "{函数}实时告警:{报警},写入队列失败。", nameof(Handle), data);
        }
    }

    private void RunAsync()
    {
        try
        {
            //记录每个路径最后一次状态处理时间
            Dictionary<DevicePath, DateTimeOffset> finalTime = [];
            // 循环从队列中获取数据
            _logger.LogTrace("{函数}:开始处理实时告警。", nameof(RunAsync));
            while (_queue.TryTake(out var data, Timeout.Infinite))
            {
                try
                {
                    // 记录日志
                    _logger.LogTrace("{函数}收到报警:{报警},开始处理。", nameof(RunAsync), data);
                    // 如果当前报警时间大于等于上次报警时间，则更新报警时间
                    // 如果finalTime字典中不存在data.SwitchInt.Path键，或者finalTime字典中data.SwitchInt.Path键对应的值小于等于data.SwitchInt.TimeStamp
                    if (!finalTime.TryGetValue(data.SwitchInt.Path, out var time) || time <= data.SwitchInt.TimeStamp)
                    {
                        // 将data.SwitchInt.TimeStamp赋值给finalTime字典中data.SwitchInt.Path键对应的值
                        finalTime[data.SwitchInt.Path] = data.SwitchInt.TimeStamp;
                    }
                    else
                    {
                        // 否则，跳过当前循环
                        _logger.LogTrace("{函数}收到报警:{报警},记录最后一次时间大于当前数据时间。", nameof(RunAsync), data);
                        continue;
                    }

                    // 根据数据类型进行处理
                    switch (data.SwitchInt.Value)
                    {
                        case Switching.Normal: // 正常状态
                            EndAlarm(data);
                            break;

                        case Switching.Alarm: // 告警状态
                            NewAlarm(data);
                            break;

                        default:
                            _logger.LogError("{函数}告警信息:{告警信息},未知类型实时告警!", nameof(RunAsync), data); // 未知类型告警
                            break;
                    }

                    AlertUpDateEvent?.Invoke(_currentAlarm.Count); // 触发更新事件
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "{函数}告警信息:{告警信息},处理失败{Message}!", nameof(RunAsync), data, ex.Message); // 记录日志
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "{函数}:处理失败{Message}!", nameof(RunAsync), ex.Message); // 记录日志
        }
    }

    private void EndAlarm(SwitchData<TAlertClassify> data)
    {
        data.AlertClassify.Count = 0;
        if (!_currentAlarm.Remove(data.SwitchInt.Path, out var alarm)) return; // 如果当前告警中移除指定路径的告警，并且成功移除，则执行以下代码
        if (_historicalRecord is null ||
            _historicalRecord.Update(alarm.Id, data.SwitchInt.TimeStamp)) // 如果更新告警历史记录成功，则执行以下代码
        {
            _realAlert.RemoveAlarm(alarm); // 从实时告警中移除该告警
            AlertEveryTimeUpDateEvent?.Invoke(_currentAlarm.Count); // 触发告警更新事件
            _logger.LogInformation("{函数}告警信息:{告警信息},成功记录恢复时间。", nameof(EndAlarm), data); // 记录日志，告警信息成功记录恢复时间
        }
        else
        {
            _currentAlarm[data.SwitchInt.Path] = alarm; // 如果更新告警恢复时间失败，则将告警重新添加到当前告警中
            _logger.LogError("{函数}告警信息:{告警信息},记录告警恢复时间失败!!{alarm}。", nameof(EndAlarm), data,
                alarm); // 记录日志，告警信息记录告警恢复时间失败
        }
    }

    private void NewAlarm(SwitchData<TAlertClassify> data)
    {
        if (data.AlertClassify.BeyondLimit > data.AlertClassify.Count)
        {
            data.AlertClassify.Count++;
            return; // 判断是否超过阈值
        }

        if (_currentAlarm.ContainsKey(data.SwitchInt.Path)) return; // 判断当前告警是否已经存在
        var alarm = _alertsFactory.Create(data); // 创建告警
        if (!_currentAlarm.TryAdd(data.SwitchInt.Path, alarm)) return; // 将告警添加到当前告警中
        if (_historicalRecord is null || _historicalRecord.Add(alarm)) // 将告警添加到告警历史中
        {
            _realAlert.AddAlarm(alarm); // 将告警添加到实时告警中
            AlertEveryTimeUpDateEvent?.Invoke(_currentAlarm.Count); // 触发告警更新事件
            _logger.LogInformation("{函数}告警信息:{告警信息},成功记录告警。", nameof(NewAlarm), data); // 记录告警信息
        }
        else
        {
            _currentAlarm.Remove(data.SwitchInt.Path); // 如果添加到告警历史失败，则将告警从当前告警中移除
            _logger.LogError("{函数}告警信息:{告警信息},添加到数据库失败{alarm}。", nameof(NewAlarm), data, alarm); // 记录告警信息
        }
    }

    ///// <summary>
    /////     清理超时告警
    ///// </summary>
    //private void ClearingAlarms()
    //{
    //    try
    //    {
    //        var storageDays =
    //            _configuration?.StorageDays ?? AlertConfiguration.DefaultStorageDays; // 获取配置文件中的存储天数，如果没有配置，则使用默认值
    //        var now = DateTimeOffset.Now; // 获取当前时间
    //        var date = now.AddDays(-storageDays); // 计算过期时间
    //        try
    //        {
    //            var len = _historicalRecord?.Delete(a => date > (a.EndTime ?? a.StartTime)); // 删除过期告警
    //            _logger.LogInformation("{函数}:当前时间{当前时间}清理{过期时间}以前过期告警,共清理{数量}条记录。", nameof(ClearingAlarms), now, date,
    //                len); // 记录日志
    //        }
    //        catch (Exception e)
    //        {
    //            _logger.LogError(e, "{函数}:当前时间{当前时间}清理{过期时间}以前过期告警失败", nameof(ClearingAlarms), now, date); // 记录错误日志
    //        }
    //    }
    //    catch (Exception e)
    //    {
    //        _logger.LogError(e, "{函数}:运行失败", nameof(ClearingAlarms)); // 记录错误日志
    //    }
    //}
}